package algo3.g203.modelo.naves;

import java.util.ArrayList;
import java.util.List;

import fiuba.algo3.titiritero.modelo.ObjetoPosicionable;
import fiuba.algo3.titiritero.modelo.ObjetoVivo;

import algo3.g203.modelo.armas.Arma;
import algo3.g203.modelo.armas.ArmaConvencional;
import algo3.g203.modelo.armas.MinaPorContacto;
import algo3.g203.modelo.armas.MinaSubmarina;
import algo3.g203.modelo.armas.explosiones.Fragmento;
import algo3.g203.modelo.fisica.Direccion;
import algo3.g203.modelo.fisica.Posicion;
import algo3.g203.modelo.naves.secciones.SeccionTemplate;

public abstract class Nave implements ObjetoVivo, ObjetoPosicionable {
	
	protected Posicion posicionProa;
	protected Posicion posicionPopa;
	protected Direccion direccionAvance;
	protected List<SeccionTemplate> listaSecciones;
	protected List<ObservadorDeNave> listaObservadores;
	protected MapaPosicionesValidas mapaPosicionesValidas;
	
	/*
	 * 
	 *   INICIALIZACION -----...........
	 * 
	 */
	
	public Nave(Posicion posicion, Direccion direccion) {
		this.posicionProa = posicion;
		this.direccionAvance = direccion;
		this.listaSecciones = new ArrayList<SeccionTemplate>();
		this.listaObservadores = new ArrayList<ObservadorDeNave>();
		this.generarSecciones();
		this.mapaPosicionesValidas = new MapaRectangular10x10();
	}
	
	private void generarSecciones() {
		
		Posicion posicionActual = this.posicionProa;
		Direccion direccionCreacion = this.direccionAvance.opuesto();
		
		for (int cantSecciones = 1; cantSecciones <= this.getTamanioNave(); cantSecciones++) {
			listaSecciones.add(this.crearSeccionEspecifica(posicionActual));
			posicionActual = direccionCreacion.siguientePosicion(posicionActual);
		}		
		
		this.posicionPopa = direccionCreacion.opuesto().siguientePosicion(posicionActual);
	
	}

	/*
	 * 
	 *   MOVIMIENTO DE NAVES -----...........
	 * 
	 */
	
	public void mover() {
		// Elijo la direccion correcta...
		Posicion proaSiguiente = this.direccionAvance.siguientePosicion(this.posicionProa);
		Posicion popaSiguiente = this.direccionAvance.siguientePosicion(this.posicionPopa);
		
		
		if (!mapaPosicionesValidas.contiene(proaSiguiente) || !mapaPosicionesValidas.contiene(popaSiguiente))
			this.direccionAvance = direccionAvance.opuesto();
		
		// ... y luego avanzo...
		this.posicionProa = this.direccionAvance.siguientePosicion(this.posicionProa);
		this.posicionPopa = this.direccionAvance.siguientePosicion(this.posicionPopa);
		for (SeccionTemplate s : this.listaSecciones)
			s.desplazarPosicion(this.direccionAvance);
	}
	
	/*
	 * 
	 *   COMPORTAMIENTOS POR DEFECTO ANTE DISPAROS -----...........
	 *   MEDIANTE DOUBLE-DISPATCH
	 * 
	 */
	
	public void recibirDisparo(Arma a) {
		a.daniar(this);
	}
	
	public void recibirDisparo(ArmaConvencional a) {
		for (Fragmento f : a.performExplosion())
			for (SeccionTemplate s: listaSecciones)
				s.recibirDanioDe(f);
	}

	public void recibirDisparo(MinaSubmarina m) {
		for (Fragmento f : m.performExplosion())
			for (SeccionTemplate s: listaSecciones)
				s.recibirDanioDe(f);
	}

	public void recibirDisparo(MinaPorContacto m) {
		for (Fragmento f : m.performExplosion())
			for (SeccionTemplate s: listaSecciones)
				s.recibirDanioDe(f);
	}
	
	/*
	 * 
	 *   CONSULTA -----...........
	 * 
	 */

	public boolean estaDestruida() {
		for(SeccionTemplate p: this.listaSecciones)
			if(!p.estaDestruida())
				return false;
		
		return true;		
	}
	
	public boolean tieneSeccionEn(Posicion p) {
		for(SeccionTemplate s: this.listaSecciones)
			if (s.estaEn(p))
				return true;
		
		return false;
	}
	
	public boolean tieneSeccionNoDaniadaEn(Posicion p) {
		for(SeccionTemplate s: this.listaSecciones)
			if (s.estaEn(p) && !s.estaDestruida())
				return true;
		
		return false;
	}

	public int cantidadSeccionesDestruidas() {
		int cantidad = 0;
		
		for (SeccionTemplate s : this.listaSecciones)
			if (s.estaDestruida())
				cantidad++;
		
		return cantidad;
	}
	
	public boolean estaEn(Posicion p) {
		for (SeccionTemplate s : this.listaSecciones)
			if (s.estaEn(p))
				return true;
		return false;
	}

	/*
	 * 
	 *   MANEJO DE PARTES DE NAVE -----...........
	 * 
	 */
		
	public SeccionTemplate getPopa() {
		return this.listaSecciones.get(this.listaSecciones.size()-1);
	}
	
	public SeccionTemplate getProa() {
		return this.listaSecciones.get(0);
	}
		
	/**
	 * TEMPLATE METHOD : Especificar la cantidad de secciones de la nave
	 */
	public abstract int getTamanioNave();
	
	/**
	 * TEMPLATE METHOD : Devolver la seccion con el que quiere ser construido la nave
	 * 
	 * @param p : La posicion de la seccion a devolver
	 */
	protected abstract SeccionTemplate crearSeccionEspecifica(Posicion p);

	public void agregarObservador(ObservadorDeNave o) {
		this.listaObservadores.add(o);
	}
	
	/**
	 * La nave tiene que decidir que hacer una vez que comienza un nuevo turno
	 * 
	 * @return : true si el si la nave fue destruida en este turno!
	 */
	public boolean comenzarTurno() {
		
		if (this.estaDestruida()) {
			for(ObservadorDeNave o : listaObservadores)
				o.notificarNaveEliminada(this);
			return true;
		}	

		this.mover();
		return false;
	}
	
	// COSAS PARA TITIRITERO
	
	@Override
	public int getX() {
		return (50*this.posicionProa.getCoordenadaX());
	}

	@Override
	public int getY() {
		return (50*this.posicionProa.getCoordenadaY());
	}
	
	public void vivir(){}

	public List<SeccionTemplate> getPartes() {
		return this.listaSecciones;
	}
	

}